<?php
/**
 * Authorization plugin, meant to be plugged in the Zend MVC dispatching loop. Works using application/Resource/Acl.php
 *
 * @see Application_Resource_Acl
 */
class Application_Controller_Plugin_Auth extends Zend_Controller_Plugin_Abstract
{
    /**
     * @var array
     */
    protected $_acl = null;

    /**
     * Assign supplied acl to instance
     * @param array $acl
     */
    public function __construct(array $acl)
    {
        $this->_acl = $acl;
    }

    /**
     * Test if web user/client is allowed to access resource, based on Acl resource
     *
     * @param Zend_Controller_Request_Abstract $request
     * @see Application_Resource_Acl
     * @return void
     */
    public function preDispatch(Zend_Controller_Request_Abstract $request)
    {
        $roles = array( 'public' );
        $auth = Zend_Auth::getInstance();

        if ($auth->hasIdentity()) {
            $roles = (array) $auth->getIdentity()->getRoles();
        }

        $authorized = false;
        $module = $request->getModuleName();
        $controller = $request->getControllerName();
        $action = $request->getActionName();

        // We cast in array, in case we get one role result from previous functions
        foreach (array_intersect(array_keys($this->_acl), $roles) as $role) {
            if ((array_key_exists($module . ':/', $this->_acl[$role])
                 && $this->_acl[$role][$module . ':/'] === true)
             or ((array_key_exists($module . ':/' . $controller, $this->_acl[$role]))
                 && $this->_acl[$role][$module . ':/' . $controller] === true)
             or ((array_key_exists($module . ':/' . $controller . '/' . $action, $this->_acl[$role]))
                 && $this->_acl[$role][$module . ':/' . $controller . '/' . $action] === true)) {
                $authorized = true;
                break;
            }
        }

        foreach (array_intersect(array_keys($this->_acl), $roles) as $role) {
            if ((array_key_exists($module . ':/', $this->_acl[$role])
                 && $this->_acl[$role][$module . ':/'] === false)
             or ((array_key_exists($module . ':/' . $controller, $this->_acl[$role]))
                 && $this->_acl[$role][$module . ':/' . $controller] === false)
             or ((array_key_exists($module . ':/' . $controller . '/' . $action, $this->_acl[$role]))
                 && $this->_acl[$role][$module . ':/' . $controller . '/' . $action] === false)) {
                $authorized = false;
                break;
            }
        }

        if (false === $authorized) {
            if ($auth->hasIdentity()) {
                $user = "User " . $auth->getIdentity()->login;
            } else {
                $user = "Non authentified user";
            }
            Application::getLogger()->log($user . ' with (' . implode(' & ', $roles) .
                    ") role(s) tried to go to {$module}/{$controller}/{$action}", Zend_Log::NOTICE);

            if (array('public') != $roles) {
                $a = new Exception("Unauthorized access", 403);
                $this->getRequest()->setControllerName('error')->setActionName('unauthorized');
            } else {
                $this->getRequest()->setControllerName('session')->setActionName('new');
            }
        }
    }
}